// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if !NET
using System.Text.RegularExpressions;
#endif
using Microsoft.CodeAnalysis;
using Microsoft.DotNet.ApiSymbolExtensions;
using Microsoft.DotNet.ApiSymbolExtensions.Filtering;
using Microsoft.DotNet.ApiSymbolExtensions.Logging;
using Microsoft.DotNet.GenAPI.SyntaxRewriter;

namespace Microsoft.DotNet.GenAPI
{
    /// <summary>
    /// Processes assembly symbols to build corresponding structures in C# language.
    /// </summary>
    public sealed class CSharpFileBuilder : IAssemblySymbolWriter
    {
        private readonly TextWriter _textWriter;
        private readonly string? _header;
        private readonly CSharpAssemblyDocumentGenerator _docGenerator;

        public const string DefaultFileHeader = """
            //------------------------------------------------------------------------------
            // <auto-generated>
            //     This code was generated by a tool.
            //
            //     Changes to this file may cause incorrect behavior and will be lost if
            //     the code is regenerated.
            // </auto-generated>
            //------------------------------------------------------------------------------

            """;

        public CSharpFileBuilder(ILog log,
                                 TextWriter textWriter,
                                 IAssemblySymbolLoader loader,
                                 ISymbolFilter symbolFilter,
                                 ISymbolFilter attributeDataSymbolFilter,
                                 string? header,
                                 string? exceptionMessage,
                                 bool includeAssemblyAttributes,
                                 IEnumerable<MetadataReference>? metadataReferences = null,
                                 bool addPartialModifier = true)
        {
            _textWriter = textWriter;
            _header = header;

            CSharpAssemblyDocumentGeneratorOptions options = new(loader, symbolFilter, attributeDataSymbolFilter)
            {
                HideImplicitDefaultConstructors = true,
                ShouldFormat = true,
                ShouldReduce = true,
                IncludeAssemblyAttributes = includeAssemblyAttributes,
                MetadataReferences = metadataReferences,
                SyntaxRewriters = [
                    new TypeDeclarationCSharpSyntaxRewriter(addPartialModifier),
                    new BodyBlockCSharpSyntaxRewriter(exceptionMessage),
                    SingleLineStatementCSharpSyntaxRewriter.Singleton
                ]
            };

            _docGenerator = new CSharpAssemblyDocumentGenerator(log, options);
        }

        /// <inheritdoc />
        public void WriteAssembly(IAssemblySymbol assemblySymbol)
        {
            _textWriter.Write(GetFormattedHeader(_header));
            Document document = _docGenerator.GetDocumentForAssemblyAsync(assemblySymbol).Result;
            SyntaxNode root = document.GetSyntaxRootAsync().Result ?? throw new InvalidOperationException(Resources.SyntaxNodeNotFound);
            root.WriteTo(_textWriter);
        }

        private static string GetFormattedHeader(string? customHeader)
        {
            if (customHeader != null)
            {
#if NET
                return customHeader.ReplaceLineEndings();
#else
            return Regex.Replace(customHeader, @"\r\n|\n\r|\n|\r", Environment.NewLine);
#endif
            }

            return DefaultFileHeader;
        }
    }
}
